package grammar.parser;

import error.processing.MyErrorProcessing;
import exp.parser.ConstExp;
import exp.parser.Exp;
import semantic.parser.SymbolTableElement;
import word.parser.WordElement;

import java.util.ArrayList;
import java.util.List;

public class VarDecl extends Decl {
    private final List<Exp> initValue;

    public VarDecl(String ident, int dimension, List<Integer> lenOfDimension, List<Exp> value) {
        super(true, ident, dimension, lenOfDimension);
        this.initValue = value;
    }

    public static List<VarDecl> buildVarDecl() {
        assert getAnalyzingWord().getType() == WordElement.WordType.INTTK;
        analyzeNextWord();
        return buildVarDef();
    }

    public static List<VarDecl> buildVarDef() {
        List<VarDecl> varDecls = new ArrayList<>();
        do {
            assert getAnalyzingWord().getType() == WordElement.WordType.IDENFR;
            String ident = getAnalyzingWord().getWord();
            int identPosition = getNowPosition();
            int dimension = 0;
            ArrayList<Integer> lenOfDimension = new ArrayList<>();
            analyzeNextWord();
            while (getAnalyzingWord().getType() == WordElement.WordType.LBRACK) {
                dimension++;
                analyzeNextWord();
                lenOfDimension.add(ConstExp.buildAndCompute().getValue());
                if (getAnalyzingWord().getType() != WordElement.WordType.RBRACK) {
                    MyErrorProcessing.buildErrorProcessing(MyErrorProcessing.ErrorType.k,
                            getAnalyzingWord(-1));
                } else {
                    analyzeNextWord();
                }
            }
            List<Exp> initVal = new ArrayList<>();
            if (getAnalyzingWord().getType() == WordElement.WordType.ASSIGN) {
                analyzeNextWord();
                initVal(initVal);
            }
            getSemanticParser().declVariable(getWord(identPosition),
                    SymbolTableElement.SymbolType.INT, getScope(),
                    dimension, lenOfDimension, new ArrayList<>(), initVal);
            varDecls.add(new VarDecl(ident, dimension, lenOfDimension, initVal));
            if (getAnalyzingWord().getType() == WordElement.WordType.COMMA) {
                analyzeNextWord();
            } else if (getAnalyzingWord().getType() == WordElement.WordType.SEMICN) {
                analyzeNextWord();
                break;
            } else {
                MyErrorProcessing.buildErrorProcessing(MyErrorProcessing.ErrorType.i, getAnalyzingWord(-1));
                break;
            }
        } while (true);
        return varDecls;
    }

    public static void initVal(List<Exp> cup) {
        if (getAnalyzingWord().getType() == WordElement.WordType.LBRACE) {
            analyzeNextWord();
            if (getAnalyzingWord().getType() != WordElement.WordType.RBRACE) {
                initVal(cup);
                while (getAnalyzingWord().getType() == WordElement.WordType.COMMA) {
                    analyzeNextWord();
                    initVal(cup);
                }
            }
            assert getAnalyzingWord().getType() == WordElement.WordType.RBRACE;
            analyzeNextWord();
        } else {
            cup.add(Exp.buildExp());
        }
    }

    @Override
    public void execute() {
        List<Integer> value = new ArrayList<>();
        for (Exp exp : initValue) {
            value.add(exp.getValue());
        }
        getSemanticParser().declVariable(getIdent(),
                SymbolTableElement.SymbolType.INT,
                getScope(), getDimension(),
                getLenOfDimension(), value);
    }
}
